package org.ytor.core.sqlflow.config;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.invoke.Reflects;
import org.ytor.core.sqlflow.BaseRepository;
import org.ytor.core.sqlflow.executor.JdbcSqlExecutor;
import org.ytor.core.sqlflow.executor.SQLRuntime;
import org.ytor.core.sqlflow.executor.SqlExecutor;
import org.ytor.core.sqlflow.executor.ds.DataSourceManager;
import org.ytor.core.sqlflow.executor.ds.SpringDataSourceManager;
import org.ytor.core.sqlflow.log.SqlLog;
import org.ytor.core.sqlflow.log.SqlLogHelper;
import org.ytor.core.sqlflow.plugin.Interceptor;
import org.ytor.core.sqlflow.plugin.InterceptorManager;

import javax.sql.DataSource;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;

/**
 * created by yangtong on 2025/8/9 14:45:45
 * <br/>
 */
@Configuration
public class SqlFlowConfig implements EnvironmentAware {

    private Environment environment;

    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @Bean
    public SqlExecutor sqlExecutor(DataSource dataSource, List<Interceptor> interceptors) {
        // 注册拦截器
        InterceptorManager.register(interceptors);

        // 创建日志记录器
        String sqlLogImpl = environment.getProperty("system.sql-flow.sql-log-impl");
        SqlLog sqlLog;
        try {
            Class<?> logClazz = Class.forName(sqlLogImpl);
            sqlLog = (SqlLog) Reflects.newInstance(logClazz);
            sqlLog.info("使用【{}】作为SQL日志记录器", sqlLog.getClass().getName());
        } catch (ClassNotFoundException | InvocationTargetException | InstantiationException |
                 IllegalAccessException e) {
            throw new BaseException(e);
        }
        SqlLogHelper.initSqlLog(sqlLog);

        DataSourceManager dsm = new SpringDataSourceManager(dataSource);
        JdbcSqlExecutor exec = new JdbcSqlExecutor(dsm);
        SQLRuntime.setExecutor(exec);
        return exec;
    }

    @Bean
    public static BeanFactoryPostProcessor makeReposDependOnSqlExecutor() {
        return bf -> {
            String[] names = bf.getBeanDefinitionNames();
            for (String name : names) {
                var bd = bf.getBeanDefinition(name);
                String className = bd.getBeanClassName();
                if (className == null) continue;
                try {
                    Class<?> clazz = Class.forName(className);
                    if (BaseRepository.class.isAssignableFrom(clazz)) {
                        String[] old = bd.getDependsOn();
                        if (old == null) {
                            bd.setDependsOn("sqlExecutor");
                        } else {
                            boolean has = false;
                            for (String o : old)
                                if ("sqlExecutor".equals(o)) {
                                    has = true;
                                    break;
                                }
                            if (!has) {
                                String[] merged = Arrays.copyOf(old, old.length + 1);
                                merged[old.length] = "sqlExecutor";
                                bd.setDependsOn(merged);
                            }
                        }
                    }
                } catch (ClassNotFoundException ignored) {
                }
            }
        };
    }
}
